package com.xiaoma.lib.store

import android.content.Context
import android.text.TextUtils
import com.google.gson.Gson
import com.tencent.mmkv.MMKV
import java.util.*

/**
 * author: liangjingbo
 * date: 2022/6/17
 * describe:
 */
internal class MMKVStore private constructor(
    context: Context,
    name: String) : IStore {
    private val mmkv: MMKV

    companion object {
        private val cacheAdapter: HashMap<String, MMKVStore> = HashMap<String, MMKVStore>()
        private val gson = Gson()

        @Synchronized
        fun getImpl(context: Context, name: String): IStore {
            val mmkvStore: MMKVStore
            if (!cacheAdapter.keys.contains(name)) {
                mmkvStore = MMKVStore(context, name)
                cacheAdapter[name] = mmkvStore
            } else {
                mmkvStore = cacheAdapter[name]!!
            }
            return mmkvStore
        }
    }

    init {
        MMKV.initialize(context)
        mmkv = MMKV.mmkvWithID(name, MMKV.MULTI_PROCESS_MODE)
    }


    override fun put(key: String, value: Any): Boolean {
        return when (value) {
            is String -> mmkv.encode(key, value)
            is Int -> mmkv.encode(key, value)
            is Boolean -> mmkv.encode(key, value)
            is Float -> mmkv.encode(key, value)
            is Double -> mmkv.encode(key, value)
            is Long -> mmkv.encode(key, value)
            else -> {
                throw RuntimeException("该方法只支持基础数据类型")
            }
        }
    }

    @Suppress("UNCHECKED_CAST")
    override fun <T> get(key: String, defaultValue: T): T {
        return when (defaultValue) {
            is String -> getString(key, defaultValue) as T
            is Int -> getInt(key, defaultValue) as T
            is Boolean -> getBoolean(key, defaultValue) as T
            is Float -> getFloat(key, defaultValue) as T
            is Double -> getDouble(key, defaultValue) as T
            is Long -> getLong(key, defaultValue) as T
            else -> {
                throw RuntimeException("该方法只支持基础数据类型")
            }
        }
    }

    override fun <T> putObject(key: String, `object`: T): Boolean {
        return mmkv.encode(key, toJson(`object`))
    }

    override fun <T> getObject(key: String, tClass: Class<T>): T? {
        val json: String? = mmkv.getString(key, "")
        return fromJson(json, tClass)
    }

    override fun <T> putList(key: String, list: List<T>?): Boolean {
        return mmkv.encode(key, toJson(list))
    }

    override fun <T> getList(key: String, tClass: Class<Array<T>>): List<T> {
        val json: String? = mmkv.getString(key, "")
        return fromJsonToList(json, tClass)
    }

    override fun contains(key: String): Boolean {
        return mmkv.contains(key)
    }

    override fun remove(key: String): Boolean {
        return mmkv.remove(key).commit()
    }

    override fun clear(): Boolean {
        return mmkv.clear().commit()
    }

    private fun getInt(key: String, defaultValue: Int = 0): Int {
        return mmkv.decodeInt(key, defaultValue)
    }

    private fun getDouble(key: String, defaultValue: Double = 0.00): Double {
        return mmkv.decodeDouble(key, defaultValue)
    }

    private fun getLong(key: String, defaultValue: Long = 0L): Long {
        return mmkv.decodeLong(key, defaultValue)
    }

    private fun getBoolean(key: String, defaultValue: Boolean = false): Boolean {
        return mmkv.decodeBool(key, defaultValue)
    }

    private fun getString(key: String, defaultValue: String = ""): String {
        return mmkv.decodeString(key, defaultValue) ?: defaultValue
    }


    private fun getFloat(key: String, defaultValue: Float = 0F): Float {
        return mmkv.decodeFloat(key, defaultValue)
    }


    private fun <T> fromJsonToList(json: String?, clazz: Class<Array<T>>): List<T> {
        return if (TextUtils.isEmpty(json)) {
            ArrayList()
        } else try {
            val arr: Array<T>? = fromJson(json, clazz)
            if (arr == null || arr.isEmpty()) {
                return ArrayList()
            }
            val ts = listOf(*arr)
            ArrayList(ts)
        } catch (e: Exception) {
            e.printStackTrace()
            ArrayList()
        }
    }


    private fun toJson(src: Any?): String? {
        return if (src == null) {
            ""
        } else try {
            gson.toJson(src)
        } catch (e: java.lang.Exception) {
            e.printStackTrace()
            ""
        }
    }

    private fun <T> fromJson(json: String?, classOfT: Class<T>): T? {
        return if (TextUtils.isEmpty(json)) {
            null
        } else try {
            gson.fromJson(json, classOfT)
        } catch (e: java.lang.Exception) {
            e.printStackTrace()
            null
        }
    }


}